<template>
  <div class="encrypt-image" :class="{ loading, fail: fail && !failSrc }" ref="encryptImage" :style="{ ...shapeStyle }">
    <img
      v-show="!loading"
      :src="url"
      :alt="alt"
      :style="{ 'object-fit': objectFit }"
      @click="onImgClick"
      @load="$emit('imgLoad')"
    />
    <slot v-if="$slots['loading'] && loading" name="loading"></slot>
  </div>
</template>

<script setup>
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { storeToRefs } from 'pinia'
import { useFullscreenPhotoStore } from '@/store/fullscreen-photo'
import { getDecryptDataBlob } from '@/utils/encrypt-img-store'
import lazyloader from '@/utils/lazyloader'

const failPlaceholder = '/images/fail-placeholder.png'

const props = defineProps({
  src: { type: String },
  fullSrc: { type: String },
  failSrc: { type: String },
  alt: { type: String },

  // 圓型
  rounded: { type: Boolean },
  radius: { type: Number },

  // 非圓形
  width: { type: Number },
  height: { type: Number },
  borderRadius: { type: Number },

  objectFit: { type: String, default: 'contain' },
  clickToFull: { type: Boolean, default: false },

  disableLazy: { type: Boolean, default: false },
})
const emits = defineEmits(['loadeddata', 'loadFail', 'imgLoad'])

const shapeStyle = computed(() => {
  if (props.rounded) {
    const lenVal = `${(props.radius * 2) / 16}rem`
    return {
      width: lenVal,
      height: lenVal,
      borderRadius: lenVal,
    }
  }

  const style = {}
  if (props.width) style.width = `${props.width / 16}rem`
  if (props.height) style.height = `${props.height / 16}rem`
  if (props.borderRadius) style.borderRadius = `${props.borderRadius / 16}rem`
  return style
})

const encryptImage = ref(null)
const loading = ref(true)
const fail = ref(false)
const decryptedUrl = ref('')
const url = computed(() => {
  if (fail.value) {
    return props.failSrc || failPlaceholder
  } else {
    return decryptedUrl.value
  }
})
onMounted(() => {
  if (props.disableLazy) {
    loadImage(props.src)
  } else {
    encryptImage.value.load = () => loadImage(props.src)
    lazyloader.observe(encryptImage.value)
  }
})
onBeforeUnmount(() => {
  lazyloader.unobserve(encryptImage.value)
})

watch(
  () => props.src,
  () => loadImage(props.src),
)

async function loadImage(src) {
  // undefined 可能是傳資料進來的時候還沒有拿到後端的值
  if (src === undefined) {
    fail.value = false
    loading.value = true
    return
  }

  // src 為空
  if (src === '' || src === null) {
    fail.value = true
    loading.value = false
    emits('loadFail')
    emits('loadeddata')
    return
  }

  try {
    decryptedUrl.value = await getDecryptDataBlob(src)
  } catch (e) {
    console.warn('EncryptImage.vue decrypt image error:', e)
    fail.value = true
    emits('loadFail')
  } finally {
    loading.value = false
    emits('loadeddata')
  }
}

const fullscreenPhotoStore = useFullscreenPhotoStore()
const { openSingle } = fullscreenPhotoStore
const { isClose } = storeToRefs(fullscreenPhotoStore)
async function onImgClick() {
  if (props.clickToFull && !loading.value && !fail.value) {
    await loadImage(props.fullSrc)
    openSingle(decryptedUrl.value)
  }
}

watch(
  () => isClose.value,
  async (newVal) => {
    if (newVal) {
      await loadImage(props.src)
    }
  },
)
</script>

<style lang="scss" scoped>
.encrypt-image {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;

  &.loading {
    background: lighten(#181925, 10%);
  }

  &.fail {
    background: linear-gradient(180deg, rgba(249, 94, 14, 0.2) 0%, rgba(231, 23, 179, 0.2) 100%);
    img {
      width: 2.875rem;
      height: 2.25rem;
    }
  }

  img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    border-radius: inherit;
  }
}
</style>
